package com.liuceng.peatio.utils

import org.apache.commons.lang3.RandomUtils
import spock.lang.Shared
import spock.lang.Specification

import java.time.LocalDateTime
import java.time.LocalTime

import static spock.util.matcher.HamcrestMatchers.closeTo
import static spock.util.matcher.HamcrestSupport.that

/**
 * Created by liyuhang on 2016-6-11.
 */
class SelfOperationChargeUtilsSpec extends Specification {
    @Shared
    def b = []
    @Shared
    def minC = []
    @Shared
    def maxC = []

    @Shared
    def totalPcs = []
    @Shared
    def adNums = []

    def setupSpec() {
        b = genRandomBidNTimes(1000)
        //
        def ctrs = genRandomCtrNTimes(1000)
        minC = ctrs[0]
        maxC = ctrs[1]
        //
        def pn = genRandomTotalPcNTimesAndAdNum(1000)
        totalPcs = pn[0]
        adNums = pn[1]
    }


    def "测试根据日期换成算成时间编码"() {
        expect: "期望结果"
        idx == SelfOperationChargeUtils.time2Index(dt)

        where:
        dt                  || idx
        LocalTime.of(0, 0)  || 1
        LocalTime.of(0, 1)  || 1
        LocalTime.of(0, 14) || 1
        LocalTime.of(0, 15) || 2
        LocalTime.of(0, 16) || 2
        LocalTime.of(1, 1)  || 5
        LocalTime.of(1, 14) || 5
        LocalTime.of(1, 15) || 6
    }

    def "测试根据时间编码换算成日期"() {
        expect: "期望结果"
        SelfOperationChargeUtils.index2Time(idx) == LocalTime.of(hour, minute)

        where:
        idx | hour | minute
        1   | 0    | 0
        2   | 0    | 15
        3   | 0    | 30
        4   | 0    | 45
        5   | 1    | 0
        6   | 1    | 15
        7   | 1    | 30
        8   | 1    | 45
        9   | 2    | 0
        10  | 2    | 15
        15  | 3    | 30
        16  | 3    | 45
        17  | 4    | 00
        20  | 4    | 45
        25  | 6    | 0
        30  | 7    | 15
        35  | 8    | 30
        41  | 10   | 0
        42  | 10   | 15
        43  | 10   | 30
        44  | 10   | 45
        60  | 14   | 45
        65  | 16   | 0
        70  | 17   | 15
        75  | 18   | 30
        88  | 21   | 45
        89  | 22   | 00
        90  | 22   | 15
        91  | 22   | 30
        92  | 22   | 45
        93  | 23   | 00
        94  | 23   | 15
        95  | 23   | 30
        96  | 23   | 45
    }

    def "test .genPV"() {
        expect:
        SelfOperationChargeUtils.genPV(pc, ctr) == pv

        where:
        pc | ctr  || pv
        1  | 0.1  || 10
        1  | 0.15 || 7
        1  | 2    || 1
        1  | 0    || 100
        3  | 0.57 || 5
        4  | 0.57 || 7
        4  | 0.13 || 31
    }


    def "test .genCTR"() {
        when:
        double ctr = SelfOperationChargeUtils.genCTR(new BigDecimal(min), new BigDecimal(max))

        then:
        ctr > min && ctr < max

        where:
        min << minC
        max << maxC
    }

    def "test .genAvgBid"() {
        when:
        double cpc = SelfOperationChargeUtils.genAvgBid(bid)

        then:
        that cpc, closeTo(bid, 0.1)

        where:
        bid << b
    }

    def "test .allocPC"() {
        when:
        Integer[] pcs = SelfOperationChargeUtils.allocPC(totalPc, num)

        then:
        //println pcs + ":" + totalPc
        Math.abs(pcs.sum() - totalPc) < 10

        where:
        totalPc << totalPcs
        num << adNums
    }

    def "test .getEPC"() {
        expect:
        SelfOperationChargeUtils.getEPC(1000, 2, idx, 0.5) == pc

        where:
        idx | pc
        1   | 0
        2   | 0
        3   | 0
        4   | 0
        5   | 0
        6   | 0
        7   | 0
        8   | 0
        9   | 0
        10  | 0
        11  | 0
        12  | 0
        13  | 0
        14  | 0
        15  | 0
        16  | 0
        17  | 0
        18  | 0
        19  | 0
        20  | 0
        21  | 0
        22  | 0
        23  | 0
        24  | 0
        25  | 0
        26  | 0
        27  | 0
        28  | 0
        29  | 0
        30  | 0
        31  | 0
        32  | 0
        33  | 0
        34  | 0
        35  | 0
        36  | 2
        37  | 7
        38  | 9
        39  | 8
        40  | 10
        41  | 12
        42  | 14
        43  | 14
        44  | 13
        45  | 13
        46  | 13
        47  | 13
        48  | 12
        49  | 12
        50  | 12
        51  | 11
        52  | 11
        53  | 11
        54  | 11
        55  | 11
        56  | 11
        57  | 11
        58  | 10
        59  | 10
        60  | 11
        61  | 11
        62  | 10
        63  | 10
        64  | 10
        65  | 12
        66  | 13
        67  | 14
        68  | 15
        69  | 15
        70  | 14
        71  | 12
        72  | 11
        73  | 9
        74  | 7
        75  | 6
        76  | 6
        77  | 6
        78  | 7
        79  | 7
        80  | 8
        81  | 7
        82  | 6
        83  | 5
        84  | 3
        85  | 2
        86  | 1
        87  | 1
        88  | 0
        89  | 0
        90  | 0
        91  | 0
        92  | 0
        93  | 0
        94  | 0
        95  | 0
        96  | 0
    }

    def "test .getRealDt"() {
        expect:
        SelfOperationChargeUtils.getRealDt(LocalDateTime.of(year, month, day, hour, minute, second)) == LocalDateTime.of(ryear, rmonth, rday, rhour, rminute, rsecond)

        where:
        year | month | day | hour | minute | second | ryear | rmonth | rday | rhour | rminute | rsecond
        2016 | 1     | 1   | 1    | 1      | 1      | 2016  | 1      | 1    | 0     | 59      | 59
        2016 | 1     | 1   | 0    | 1      | 1      | 2015  | 12     | 31   | 23    | 59      | 59
        2016 | 1     | 1   | 12   | 12     | 12     | 2016  | 1      | 1    | 11    | 59      | 59
        2016 | 10    | 10  | 23   | 34     | 23     | 2016  | 10     | 10   | 23    | 29      | 59
    }

    // helper methods

    //随机生成N个总点击量
    def genRandomTotalPcNTimesAndAdNum(n) {
        def totalPcs = []
        def adNums = []
        n.times {
            totalPcs << RandomUtils.nextInt(0, 20)
            adNums << RandomUtils.nextInt(1, 5)
        }

        return [totalPcs, adNums]
    }

    //随机生成N个出价
    def genRandomBidNTimes(n) {
        def tmp = []
        n.times {
            tmp << RandomUtils.nextDouble(1.0, 5.0) //在1.0元到5.0元区间内生成出价
        }
        return tmp
    }

    //随机生成N个ctr的最小和最大值
    def genRandomCtrNTimes(n) {
        def tmpMin = []
        def tmpMax = []

        n.times {
            double a = Math.random()
            double b = Math.random()
            double min = 0.0
            double max = 0.0
            if (a > b) {
                min = b
                max = a
            } else {
                min = a
                max = b
            }
            tmpMin << min
            tmpMax << max
        }
        return [tmpMin, tmpMax]
    }
}